<?php


use Illuminate\Support\Facades\Input;
use Illuminate\Support\Facades\Redirect;
use Overtrue\Wechat\Payment;
use Overtrue\Wechat\Payment\Business;
use Overtrue\Wechat\Payment\UnifiedOrder;
use Illuminate\Support\Facades\Request;


include_once  app_path() . '/pay/union/func/common.php';
// include_once  app_path() . '/pay/union/func/SDKConfig.php';
include_once  app_path() . '/pay/union/func/secureUtil.php';
include_once  app_path() . '/pay/union/func/httpClient.php';
include_once  app_path() . '/pay/union/func/log.class.php';

require_once app_path().'/pay/alipay/AlipayTradeService.php';
require_once app_path().'/pay/alipay/AlipayTradeWapPayContentBuilder.php';
require_once app_path().'/pay/alipay/AlipayTradePagePayContentBuilder.php';
require_once app_path().'/pay/alipay/AopSdk.php';


class PayController  extends BaseController {
	
	protected $layout = 'layouts.front';
	
	
	public function showOrderPay($id){
		//订单支付
		$content = $this->makeView('front.order-pay');
		$this->layout->content = $content;
	
		$order = Order::with("products.product")->find($id);
		$subject = "";
		$order->products->each(function($p) use (&$subject){
			$subject = $subject.$p->product->name."|";
		});
		$subject=substr($subject,0,-1);
		$subject = str_limit($subject, 128, "...");
		$content->with("order",$order);
		$content->with("subject",$subject);
		
		/**
		 * 如果是微信浏览器，需要授权
		 */
		if ($this->isWeixin()){
			$userId = Auth::id();
			$user = User::find($userId);
			
			$appId = Config::get("mao.wxpay.app_id");
			$appKey = Config::get("mao.wxpay.app_key");
			//没有授权过，需要通过授权获取open_id
			$userId = "aaaa".Auth::id() ."bbbb";
			$openId = Session::get($userId);
			if (empty($openId)) {
				$auth = new Overtrue\Wechat\Auth($appId,$appKey);
				//重定向到微信授权页面
				$redirectURL = Config::get("mao.wxpay.redirect_url");
				$url = $auth->url($redirectURL,"snsapi_base");
				//Log::error("$url");
				//$auth->redirect($redirectURL,"snsapi_base");
				Session::flash('original-url', Request::url());
				return Redirect::to($url);
			}
			
			/**
			 * 第 1 步：定义商户
			 */
			$business = new Business(
					$appId,$appKey,
					Config::get("mao.wxpay.mch_id"),
					Config::get("mao.wxpay.mch_key")
			);
			
			/**
			 * 第 2 步：定义订单
			*/
			$payOrder = new Overtrue\Wechat\Payment\Order();
			$payOrder->body = $subject;
			$payOrder->out_trade_no = $order->id;
			$payOrder->total_fee = strval(($order->freight + $order->product_total_price) * 100);    // 单位为 “分”, 字符串类型
			$payOrder->openid = $openId;
			$payOrder->notify_url = Config::get("mao.wxpay.notify");
			
			/**
			 * 第 3 步：统一下单
			 */
			$unifiedOrder = new UnifiedOrder($business, $payOrder);
			
			/**
			 * 第 4 步：生成支付配置文件
			*/
			$payment = new Payment($unifiedOrder);
			$params = $payment->getConfig();
			//Log::error($params);
			$content->with("wxparams",$params);
		}
	}
	
	/**
	 * 用户选择支付类型后，开始启用支付
	 * @return string
	 */
	public function postOrderPay(){
		
// 		$pay_type = Input::get("pay_type");
		
		
// 		if ($pay_type == 1){
// 			//阿里支付
// 			return $this->postOrderPayByAlipay();
// 		} else {
// 			//网银支付
// 			return $this->postOrderPayByAlipayBank();
// 		}

		if ($this->isMobile()){
			$this->postOrderPayForWap();
		} else {
			$this->postOrderPayForPC();
		}
		
	}
	
	private function postOrderPayForWap(){
		$config = Config::get("mao.alipay");
		//商户网站订单系统中唯一订单号，必填
		$out_trade_no= Input::get('out_trade_no');
		//订单名称,必填
		$subject= Input::get('subject');
	
		//付款金额,必填
		$total_fee = Input::get('total_fee');
	
		$payRequestBuilder = new AlipayTradeWapPayContentBuilder();
		$payRequestBuilder->setSubject($subject);
		$payRequestBuilder->setOutTradeNo($out_trade_no);
		$payRequestBuilder->setTotalAmount($total_fee);
		//超时时间
		$timeout_express="1m";
		$payRequestBuilder->setTimeExpress($timeout_express);
	
		$payResponse = new AlipayTradeService($config);
		$result=$payResponse->wapPay($payRequestBuilder,$config['return_url'],$config['notify_url']);
	
	}
	
	private function postOrderPayForPC(){
		$config = Config::get("mao.alipay");
		
		//商户网站订单系统中唯一订单号，必填
		$out_trade_no= Input::get('out_trade_no');
		//订单名称,必填
		$subject= Input::get('subject');
		
		//付款金额,必填
		$total_fee = Input::get('total_fee');
		
		//构造参数
		$payRequestBuilder = new AlipayTradePagePayContentBuilder();
		$payRequestBuilder->setSubject($subject);
		$payRequestBuilder->setTotalAmount($total_fee);
		$payRequestBuilder->setOutTradeNo($out_trade_no);
		$aop = new AlipayTradeService($config);
		/**
		 * pagePay 电脑网站支付请求
		 * @param $builder 业务参数，使用buildmodel中的对象生成。
		 * @param $return_url 同步跳转地址，公网可以访问
		 * @param $notify_url 异步通知地址，公网可以访问
		 * @return $response 支付宝返回的信息
		*/
		$response = $aop->pagePay($payRequestBuilder,$config['return_url'],$config['notify_url']);
		
	}
	
	
// 	private function postOrderPayByAlipayBank(){
// 		$pay_param = Config::get("mao.alipay.pay_bank");
// 		//商户网站订单系统中唯一订单号，必填
// 		$pay_param['out_trade_no'] = Input::get('out_trade_no');
		
// 		//订单名称,必填
// 		$pay_param['subject'] = Input::get('subject');
		
// 		//付款金额,必填
// 		$pay_param['total_fee'] = Input::get('total_fee');
// 		//
		
// 		//订单描述
// 		//$body = $_POST['WIDbody'];
// 		//商品展示地址
// 		$pay_param['show_url'] = 'http://www.maggiemaostudio.com/order/'.$pay_param['out_trade_no'];
// 		//需以http://开头的完整路径，例如：http://www.商户网址.com/myorder.html
		
// 		//防钓鱼时间戳
// 		//$anti_phishing_key = "";
// 		//若要使用请调用类文件submit中的query_timestamp函数
		
// 		//客户端的IP地址
// 		//$exter_invoke_ip = "";
// 		//非局域网的外网IP地址，如：221.0.0.1
		
		
// 		//默认网银
// 		$pay_param['defaultbank'] = Input::get('pay_type');
		
// 		//建立请求
// 		$alipay = new Alipay($pay_param);
// 		return  $alipay->request($pay_param);
// 	}

	
	
// 老版本支付宝支付
// 	private function postOrderPayByAlipay(){
		
// 		$pay_param = Config::get("mao.alipay.pay_param");
// 		if ($this->isMobile()){
// 			$pay_param = Config::get("mao.alipay.pay_wap");
// 		}
// 		//商户网站订单系统中唯一订单号，必填
// 		$pay_param['out_trade_no'] = Input::get('out_trade_no');
		
// 		//订单名称,必填
// 		$pay_param['subject'] = Input::get('subject');
		
// 		//付款金额,必填
// 		$pay_param['total_fee'] = Input::get('total_fee');
// 		//
		
// 		//订单描述
// 		//$body = $_POST['WIDbody'];
// 		//商品展示地址
// 		$pay_param['show_url'] = 'http://www.maggiemaostudio.com/order/'.$pay_param['out_trade_no'];
// 		//需以http://开头的完整路径，例如：http://www.商户网址.com/myorder.html
		
// 		//防钓鱼时间戳
// 		//$anti_phishing_key = "";
// 		//若要使用请调用类文件submit中的query_timestamp函数
		
// 		//客户端的IP地址
// 		//$exter_invoke_ip = "";
// 		//非局域网的外网IP地址，如：221.0.0.1
		
// 		//建立请求
// 		$alipay = new Alipay($pay_param);
// 		return  $alipay->request($pay_param);
// 	}
	
	
	

	
	
// 	public function showOrderPayReturn(){
// 			//计算得出通知验证结果
// 		$alipay = new Alipay();
// 		if($alipay->verifyReturn()) {//验证成功
// 			/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// 			//请在这里加上商户的业务逻辑程序代码
			
// 			//——请根据您的业务逻辑来编写程序（以下代码仅作参考）——
// 		    //获取支付宝的通知返回参数，可参考技术文档中页面跳转同步通知参数列表
		
// 			//商户订单号
// 			$out_trade_no = Input::get('out_trade_no');
		
// 			//支付宝交易号
// 			$trade_no =  Input::get('trade_no');
		
// 			//交易状态
// 			$trade_status = Input::get('trade_status');
			
// 			Log::info("return,trade_status=".$trade_status.",order_id=".$out_trade_no);
// 		    if($trade_status == 'TRADE_FINISHED' || $trade_status == 'TRADE_SUCCESS') {
// 				//判断该笔订单是否在商户网站中已经做过处理
// 				//如果没有做过处理，根据订单号（out_trade_no）在商户网站的订单系统中查到该笔订单的详细，并执行商户的业务程序
// 				//如果有做过处理，不执行商户的业务程序
// 				$this->handleOrderPaySuccess($out_trade_no, $trade_no, 1);
// 		    	return Redirect::to("user/order-list");
// 		    }
// 		    else {
// 		      return "支付失败";
// 		    }
// 			//——请根据您的业务逻辑来编写程序（以上代码仅作参考）——
// 			/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// 		}
// 		else {
// 		    //验证失败
// 		    //如要调试，请看alipay_notify.php页面的verifyReturn函数
// 			//验证失败
// 			$data = Input::all();
// 			$data['client2_ip'] = $this->getClientIP();
// 			Log::error("非法请求",$data);
// 		    return "非法请求";
// 		}
// 	}
	
	
	public function showOrderPayReturn(){
		$config = $config = Config::get("mao.alipay");
		$alipaySevice = new AlipayTradeService($config);
		
		$data = Input::all();
		$result = $alipaySevice->check($data);
		
		/* 实际验证过程建议商户添加以下校验。
		 1、商户需要验证该通知数据中的out_trade_no是否为商户系统中创建的订单号，
		2、判断total_amount是否确实为该订单的实际金额（即商户订单创建时的金额），
		3、校验通知中的seller_id（或者seller_email) 是否为out_trade_no这笔单据的对应的操作方（有的时候，一个商户可能有多个seller_id/seller_email）
		4、验证app_id是否为该商户本身。
		*/
		if($result) {//验证成功
			/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
			//请在这里加上商户的业务逻辑程序代码
		
			//——请根据您的业务逻辑来编写程序（以下代码仅作参考）——
			//获取支付宝的通知返回参数，可参考技术文档中页面跳转同步通知参数列表
			//商户订单号
			$out_trade_no = Input::get('out_trade_no');
			
			//支付宝交易号
			$trade_no =  Input::get('trade_no');
			
			//交易状态
			$trade_status = Input::get('trade_status');
				
			Log::info("return,trade_status=".$trade_status.",order_id=".$out_trade_no);
			if($trade_status == 'TRADE_FINISHED' || $trade_status == 'TRADE_SUCCESS') {
				//判断该笔订单是否在商户网站中已经做过处理
				//如果没有做过处理，根据订单号（out_trade_no）在商户网站的订单系统中查到该笔订单的详细，并执行商户的业务程序
				//如果有做过处理，不执行商户的业务程序
				$this->handleOrderPaySuccess($out_trade_no, $trade_no, 1);
				return Redirect::to("user/order-list");
			}
			else {
				return "支付失败";
			}
		}
		else {
			$data['client2_ip'] = $this->getClientIP();
			Log::error("非法请求",$data);
			//验证失败
			return "验证失败";
		}
	}
	
	private function handleOrderPaySuccess($orderId,$trade_no,$payType){
		$order = Order::where("status",'=',0)->where("id","=",$orderId)->first();
		if (!empty($order)){
			$order->update(array('pay_type'=>$payType,'trade_no'=>$trade_no,'status'=>1));
			//邮件通知
			Mail::queue('emails.order_notify', array("id"=>$orderId), function($message){
				$message->to('info@maggiemaostudio.com', 'Maggiemaostudio')->subject('新订单通知!');
			});
		}
	}
	
	public function postOrderPayNotify(){
		$config = $config = Config::get("mao.alipay");
		$alipaySevice = new AlipayTradeService($config);
// 		$alipaySevice->writeLog(var_export($_POST,true));

		$data = Input::all();
		$result = $alipaySevice->check($data);
		
		/* 实际验证过程建议商户添加以下校验。
		 1、商户需要验证该通知数据中的out_trade_no是否为商户系统中创建的订单号，
		2、判断total_amount是否确实为该订单的实际金额（即商户订单创建时的金额），
		3、校验通知中的seller_id（或者seller_email) 是否为out_trade_no这笔单据的对应的操作方（有的时候，一个商户可能有多个seller_id/seller_email）
		4、验证app_id是否为该商户本身。
		*/
		if($result) {//验证成功
			/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
			//请在这里加上商户的业务逻辑程序代
			//——请根据您的业务逻辑来编写程序（以下代码仅作参考）——
			//获取支付宝的通知返回参数，可参考技术文档中服务器异步通知参数列表
			//商户订单号
			$out_trade_no = $data['out_trade_no'];
			//支付宝交易号
			$trade_no = $data['trade_no'];
			//交易状态
			$trade_status = $data['trade_status'];
		
			if($data['trade_status'] == 'TRADE_FINISHED') {
		
				//判断该笔订单是否在商户网站中已经做过处理
				//如果没有做过处理，根据订单号（out_trade_no）在商户网站的订单系统中查到该笔订单的详细，并执行商户的业务程序
				//请务必判断请求时的total_amount与通知时获取的total_fee为一致的
				//如果有做过处理，不执行商户的业务程序
				//注意：
				//退款日期超过可退款期限后（如三个月可退款），支付宝系统发送该交易状态通知
				$this->handleOrderPaySuccess($out_trade_no, $trade_no, 1);
			}
			else if ($data['trade_status'] == 'TRADE_SUCCESS') {
				//判断该笔订单是否在商户网站中已经做过处理
				//如果没有做过处理，根据订单号（out_trade_no）在商户网站的订单系统中查到该笔订单的详细，并执行商户的业务程序
				//请务必判断请求时的total_amount与通知时获取的total_fee为一致的
				//如果有做过处理，不执行商户的业务程序
				//注意：
				//付款完成后，支付宝系统发送该交易状态通知
				$this->handleOrderPaySuccess($out_trade_no, $trade_no, 1);
			}
			//——请根据您的业务逻辑来编写程序（以上代码仅作参考）——
			return "success";		//请不要修改或删除
		
		}else {
			$data['client2_ip'] = $this->getClientIP();
			Log::error("非法请求",$data);
			//验证失败
			return "fail";	//请不要修改或删除
		
		}
		
	}
	
// 	public function postOrderPayNotify(){
// 		//计算得出通知验证结果
// 		$alipay = new Alipay();
		
// 		if($alipay->verifyNotify()) {//验证成功
// 			/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// 			//请在这里加上商户的业务逻辑程序代
// 			//——请根据您的业务逻辑来编写程序（以下代码仅作参考）——
// 		    //获取支付宝的通知返回参数，可参考技术文档中服务器异步通知参数列表
			
// 			//商户订单号
// 			$out_trade_no = Input::get('out_trade_no');
		
// 			//支付宝交易号
// 			$trade_no =  Input::get('trade_no');
		
// 			//交易状态
// 			$trade_status = Input::get('trade_status');
		
		
// 		    if($trade_status == 'TRADE_FINISHED') {
// 				//判断该笔订单是否在商户网站中已经做过处理
// 					//如果没有做过处理，根据订单号（out_trade_no）在商户网站的订单系统中查到该笔订单的详细，并执行商户的业务程序
// 					//如果有做过处理，不执行商户的业务程序
						
// 				//注意：
// 				//该种交易状态只在两种情况下出现
// 				//1、开通了普通即时到账，买家付款成功后。
// 				//2、开通了高级即时到账，从该笔交易成功时间算起，过了签约时的可退款时限（如：三个月以内可退款、一年以内可退款等）后。
		
// 		        //调试用，写文本函数记录程序运行情况是否正常
// 		        //logResult("这里写入想要调试的代码变量值，或其他运行的结果记录");
// 		    	$this->handleOrderPaySuccess($out_trade_no, $trade_no, 1);
// 		    	//return Redirect::to("user/order-list");
// 		    }
// 		    else if ($trade_status == 'TRADE_SUCCESS') {
// 				//判断该笔订单是否在商户网站中已经做过处理
// 					//如果没有做过处理，根据订单号（out_trade_no）在商户网站的订单系统中查到该笔订单的详细，并执行商户的业务程序
// 					//如果有做过处理，不执行商户的业务程序
						
// 				//注意：
// 				//该种交易状态只在一种情况下出现——开通了高级即时到账，买家付款成功后。
		
// 		        //调试用，写文本函数记录程序运行情况是否正常
// 		        //logResult("这里写入想要调试的代码变量值，或其他运行的结果记录");
// 		    	$this->handleOrderPaySuccess($out_trade_no, $trade_no, 1);
// 		    	//return Redirect::to("user/order-list");
// 		    }
// 			Log::info("notify,trade_status=".$trade_status.",order_id=".$out_trade_no);
// 			//——请根据您的业务逻辑来编写程序（以上代码仅作参考）——
// 			return "success";		//请不要修改或删除
// 		}
// 		else {
// 		    //验证失败
// 		    $data = Input::all();
// 		    $data['client2_ip'] = $this->getClientIP();
// 		    Log::error("非法请求",$data);
// 		    return "非法请求";
// 		    //调试用，写文本函数记录程序运行情况是否正常
// 		    //logResult("这里写入想要调试的代码变量值，或其他运行的结果记录");
// 		}
// 	}
	
	private function getClientIP(){
		if (array_key_exists("HTTP_X_FORWARDED_FOR",$_SERVER))
			$ip = $_SERVER["HTTP_X_FORWARDED_FOR"];
		else if (array_key_exists("HTTP_CLIENT_IP",$_SERVER))
			$ip = $_SERVER["HTTP_CLIENT_IP"];
		else if (array_key_exists("REMOTE_ADDR",$_SERVER))
			$ip = $_SERVER["REMOTE_ADDR"];
		else if (getenv("HTTP_X_FORWARDED_FOR"))
			$ip = getenv("HTTP_X_FORWARDED_FOR");
		else if (getenv("HTTP_CLIENT_IP"))
			$ip = getenv("HTTP_CLIENT_IP");
		else if (getenv("REMOTE_ADDR")) //PHP开源代码
			$ip = getenv("REMOTE_ADDR");
		else
			$ip = "Unknown";
		return $ip;
	}
}

class Alipay{
	/**
	 * 建立请求，以表单HTML形式构造（默认）
	 * @param $para_temp 请求参数数组
	 * @param $method 提交方式。两个值可选：post、get
	 * @param $button_name 确认按钮显示文字
	 * @return 提交表单HTML文本
	 */
	public function request($para_temp) {
		//待请求参数数组
		$para = $this->buildRequestPara($para_temp);
	
		$sHtml = "<div style='font-size:12px;'>正在提交到支付宝。。。</div><form id='alipaysubmit' name='alipaysubmit' action='".Config::get("mao.alipay.gateway_new")."' method='get'>";
		while (list ($key, $val) = each ($para)) {
			$sHtml.= "<input type='hidden' name='".$key."' value='".$val."'/>";
		}
	
		//submit按钮控件请不要含有name属性
		$sHtml = $sHtml."</form>";
	
		$sHtml = $sHtml."<script>document.forms['alipaysubmit'].submit();</script>";
	
		return $sHtml;
	}

	
	/**
	 * 生成要请求给支付宝的参数数组
	 * @param $para_temp 请求前的参数数组
	 * @return 要请求的参数数组
	 */
	private function buildRequestPara($para_temp) {
		//除去待签名参数数组中的空值和签名参数
		$para_filter = $this->paraFilter($para_temp);
	
		//对待签名参数数组排序
		$para_sort = $this->argSort($para_filter);
	
		//生成签名结果
		$mysign = $this->buildRequestMysign($para_sort);
	
		//签名结果与签名方式加入请求提交参数组中
		$para_sort['sign'] = $mysign;
		$para_sort['sign_type'] = Config::get('mao.alipay.sign_type');
		return $para_sort;
	}
	

	/**
	 * 生成签名结果
	 * @param $para_sort 已排序要签名的数组
	 * return 签名结果字符串
	 */
	private function buildRequestMysign($para_sort) {
		//把数组所有元素，按照“参数=参数值”的模式用“&”字符拼接成字符串
		$prestr = $this->createLinkstring($para_sort);
		$mysign = $this->md5Sign($prestr, Config::get('mao.alipay.key'));
		return $mysign;
	}
	
	/**
	 * 签名字符串
	 * @param $prestr 需要签名的字符串
	 * @param $key 私钥
	 * return 签名结果
	 */
	private function md5Sign($prestr, $key) {
		$prestr = $prestr . $key;
		return md5($prestr);
	}
	
	/**
	 * 验证签名
	 * @param $prestr 需要签名的字符串
	 * @param $sign 签名结果
	 * @param $key 私钥
	 * return 签名结果
	 */
	private function md5Verify($prestr, $sign, $key) {
		$prestr = $prestr . $key;
		$mysgin = md5($prestr);
	
		if($mysgin == $sign) {
			return true;
		}
		else {
			return false;
		}
	}
	
	/**
	 * 把数组所有元素，按照“参数=参数值”的模式用“&”字符拼接成字符串
	 * @param $para 需要拼接的数组
	 * return 拼接完成以后的字符串
	 */
	private function createLinkstring($para) {
		$arg  = "";
		while (list ($key, $val) = each ($para)) {
			$arg.=$key."=".$val."&";
		}
		//去掉最后一个&字符
		$arg = substr($arg,0,count($arg)-2);
	
		//如果存在转义字符，那么去掉转义
		if(get_magic_quotes_gpc()){$arg = stripslashes($arg);}
	
		return $arg;
	}
	
	/**
	 * 除去数组中的空值和签名参数
	 * @param $para 签名参数组
	 * return 去掉空值与签名参数后的新签名参数组
	 */
	private function paraFilter($para) {
		$para_filter = array();
		while (list ($key, $val) = each ($para)) {
			if($key == "sign" || $key == "sign_type" || $val == "")continue;
			else	$para_filter[$key] = $para[$key];
		}
		return $para_filter;
	}
	/**
	 * 对数组排序
	 * @param $para 排序前的数组
	 * return 排序后的数组
	 */
	private function argSort($para) {
		ksort($para);
		reset($para);
		return $para;
	}
	
	/**
	 * 针对return_url验证消息是否是支付宝发出的合法消息
	 * @return 验证结果
	 */
	public function verifyReturn(){
		$data = Input::all();
		if(empty($data)) {
			return false;
		}
		else {
			//生成签名结果
			$sign = Input::get("sign","");
			$isSign = $this->getSignVeryfy($data, $sign);
			//获取支付宝远程服务器ATN结果（验证是否是支付宝发来的消息）
			$responseTxt = 'true';
			$notify_id = Input::get("notify_id","");
			if (!empty($notify_id)){
				$responseTxt = $this->getResponse($notify_id);
			}
			
			//写日志记录
			//if ($isSign) {
			//	$isSignStr = 'true';
			//}
			//else {
			//	$isSignStr = 'false';
			//}
			//$log_text = "responseTxt=".$responseTxt."\n return_url_log:isSign=".$isSignStr.",";
			//$log_text = $log_text.createLinkString($_GET);
			//logResult($log_text);
				
			//验证
			//$responsetTxt的结果不是true，与服务器设置问题、合作身份者ID、notify_id一分钟失效有关
			//isSign的结果不是true，与安全校验码、请求时的参数格式（如：带自定义参数等）、编码格式有关
			if (preg_match("/true$/i",$responseTxt) && $isSign) {
				return true;
			} else {
				return false;
			}
		}
	}
	
	/**
	 * 针对notify_url验证消息是否是支付宝发出的合法消息
	 * @return 验证结果
	 */
	public function verifyNotify(){
		$data = Input::all();
		if(empty($data)) {//判断POST来的数组是否为空
			return false;
		}
		else {
			//生成签名结果
			$sign = Input::get("sign","");
			$isSign = $this->getSignVeryfy($data, $sign);
			//获取支付宝远程服务器ATN结果（验证是否是支付宝发来的消息）
			$responseTxt = 'true';
			$notify_id = Input::get("notify_id","");
			if (!empty($notify_id)){
				$responseTxt = $this->getResponse($notify_id);
			}
				
			//写日志记录
			//if ($isSign) {
			//	$isSignStr = 'true';
			//}
			//else {
			//	$isSignStr = 'false';
			//}
			//$log_text = "responseTxt=".$responseTxt."\n notify_url_log:isSign=".$isSignStr.",";
			//$log_text = $log_text.createLinkString($_POST);
			//logResult($log_text);
				
			//验证
			//$responsetTxt的结果不是true，与服务器设置问题、合作身份者ID、notify_id一分钟失效有关
			//isSign的结果不是true，与安全校验码、请求时的参数格式（如：带自定义参数等）、编码格式有关
			if (preg_match("/true$/i",$responseTxt) && $isSign) {
				return true;
			} else {
				return false;
			}
		}
	}
	
	/**
	 * 获取返回时的签名验证结果
	 * @param $para_temp 通知返回来的参数数组
	 * @param $sign 返回的签名结果
	 * @return 签名验证结果
	 */
	private function getSignVeryfy($para_temp, $sign) {
		//除去待签名参数数组中的空值和签名参数
		$para_filter = $this->paraFilter($para_temp);
	
		//对待签名参数数组排序
		$para_sort = $this->argSort($para_filter);
	
		//把数组所有元素，按照“参数=参数值”的模式用“&”字符拼接成字符串
		$prestr = $this->createLinkstring($para_sort);
	
		$isSign = $this->md5Verify($prestr, $sign, Config::get("mao.alipay.key"));
		return $isSign;
	}
	
	/**
	 * 获取远程服务器ATN结果,验证返回URL
	 * @param $notify_id 通知校验ID
	 * @return 服务器ATN结果
	 * 验证结果集：
	 * invalid命令参数不对 出现这个错误，请检测返回处理中partner和key是否为空
	 * true 返回正确信息
	 * false 请检查防火墙或者是服务器阻止端口问题以及验证时间是否超过一分钟
	 */
	function getResponse($notify_id) {
// 		$transport = strtolower(trim($this->alipay_config['transport']));
		$transport = Config::get("mao.alipay.transport");
		$partner = Config::get("mao.alipay.partner");
		$veryfy_url = '';
		if($transport == 'https') {
			$veryfy_url = Config::get('mao.alipay.https_verify_url');
		}
		else {
			$veryfy_url = Config::get('mao.alipay.http_verify_url');
		}
		$veryfy_url = $veryfy_url."partner=" . $partner . "&notify_id=" . $notify_id;
		$responseTxt = $this->getHttpResponseGET($veryfy_url, Config::get('mao.alipay.cacert'));
	
		return $responseTxt;
	}
	
	/**
	 * 远程获取数据，GET模式
	 * 注意：
	 * 1.使用Crul需要修改服务器中php.ini文件的设置，找到php_curl.dll去掉前面的";"就行了
	 * 2.文件夹中cacert.pem是SSL证书请保证其路径有效，目前默认路径是：getcwd().'\\cacert.pem'
	 * @param $url 指定URL完整路径地址
	 * @param $cacert_url 指定当前工作目录绝对路径
	 * return 远程输出的数据
	 */
	private function getHttpResponseGET($url,$cacert_url) {
		$curl = curl_init($url);
		curl_setopt($curl, CURLOPT_HEADER, 0 ); // 过滤HTTP头
		curl_setopt($curl,CURLOPT_RETURNTRANSFER, 1);// 显示输出结果
		curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, true);//SSL证书认证
		curl_setopt($curl, CURLOPT_SSL_VERIFYHOST, 2);//严格认证
		curl_setopt($curl, CURLOPT_CAINFO,$cacert_url);//证书地址
		$responseText = curl_exec($curl);
		//var_dump( curl_error($curl) );//如果执行curl过程中出现异常，可打开此开关，以便查看异常内容
		curl_close($curl);
	
		return $responseText;
	}
	/**
	 * 生成要请求给支付宝的参数数组
	 * @param $para_temp 请求前的参数数组
	 * @return 要请求的参数数组字符串
	 */
	function buildRequestParaToString($para_temp) {
		//待请求参数数组
		$para = $this->buildRequestPara($para_temp);
	
		//把参数组中所有元素，按照“参数=参数值”的模式用“&”字符拼接成字符串，并对字符串做urlencode编码
		$request_data = createLinkstringUrlencode($para);
	
		return $request_data;
	}
	
	
	
	/**
	 * 建立请求，以模拟远程HTTP的POST请求方式构造并获取支付宝的处理结果
	 * @param $para_temp 请求参数数组
	 * @return 支付宝处理结果
	 */
	function buildRequestHttp($para_temp) {
		$sResult = '';
	
		//待请求参数数组字符串
		$request_data = $this->buildRequestPara($para_temp);
	
		//远程获取数据
		$sResult = getHttpResponsePOST($this->alipay_gateway_new, $this->alipay_config['cacert'],$request_data,trim(strtolower($this->alipay_config['input_charset'])));
	
		return $sResult;
	}
	
	/**
	 * 建立请求，以模拟远程HTTP的POST请求方式构造并获取支付宝的处理结果，带文件上传功能
	 * @param $para_temp 请求参数数组
	 * @param $file_para_name 文件类型的参数名
	 * @param $file_name 文件完整绝对路径
	 * @return 支付宝返回处理结果
	 */
	function buildRequestHttpInFile($para_temp, $file_para_name, $file_name) {
	
		//待请求参数数组
		$para = $this->buildRequestPara($para_temp);
		$para[$file_para_name] = "@".$file_name;
	
		//远程获取数据
		$sResult = getHttpResponsePOST($this->alipay_gateway_new, $this->alipay_config['cacert'],$para,trim(strtolower($this->alipay_config['input_charset'])));
	
		return $sResult;
	}
	
	/**
	 * 用于防钓鱼，调用接口query_timestamp来获取时间戳的处理函数
	 * 注意：该功能PHP5环境及以上支持，因此必须服务器、本地电脑中装有支持DOMDocument、SSL的PHP配置环境。建议本地调试时使用PHP开发软件
	 * return 时间戳字符串
	 */
	function query_timestamp() {
		$url = $this->alipay_gateway_new."service=query_timestamp&partner=".trim(strtolower($this->alipay_config['partner']))."&_input_charset=".trim(strtolower($this->alipay_config['input_charset']));
		$encrypt_key = "";
	
		$doc = new DOMDocument();
		$doc->load($url);
		$itemEncrypt_key = $doc->getElementsByTagName( "encrypt_key" );
		$encrypt_key = $itemEncrypt_key->item(0)->nodeValue;
	
		return $encrypt_key;
	}
}